#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU Lesser General Public License.
/// </copyright>
#pragma endregion

#pragma once

//static const wchar_t* HeaderContentEncoding = L"Content-Encoding";
static const wchar_t* HeaderContentType = L"Content-Type";

class HttpHeaderCollection
{
private:
	CSimpleMap<CString, CSimpleArray<CString> > _headers;

public:

	HttpHeaderCollection()
	{
	}

	HRESULT Set(const wchar_t* key, const wchar_t* value)
	{
		int index = _headers.FindKey(key);
		if(index != -1)
		{
			_headers.GetValueAt(index).RemoveAll();
			_headers.GetValueAt(index).Add(value);
		}
		else
		{
			_headers.Add(key, CSimpleArray<CString>());
			_headers.GetValueAt(_headers.GetSize() - 1).Add(value);
		}
		return S_OK;
	}

	HRESULT Set(const wchar_t* key, CSimpleArray<CString>& value)
	{
		int index = _headers.FindKey(key);
		if(index != -1)
			_headers.SetAt(key, value);
		else
			_headers.Add(key, value);
		return S_OK;
	}

	HRESULT Add(const wchar_t* key, const wchar_t* value)
	{
		int index = _headers.FindKey(key);
		if(index != -1)
		{
			_headers.GetValueAt(index).Add(value);
		}
		else
		{
			_headers.Add(key, CSimpleArray<CString>());
			_headers.GetValueAt(_headers.GetSize() - 1).Add(value);
		}
		return S_OK;
	}

	HRESULT AddHeaders(const wchar_t* headers)
	{
		int headersLen = (int)wcslen(headers);
		if(headers == NULL || headersLen == 0)
			return S_OK;

		CSimpleMap<CString, CSimpleArray<CString> > newHeaders;
		const wchar_t* nextHeaderStart = headers;
		do
		{
			const wchar_t* nextHeaderEnd = wcsstr(nextHeaderStart, L"\r\n");
			if(nextHeaderEnd == NULL)
				nextHeaderEnd = headers + headersLen;

			if(nextHeaderStart >= nextHeaderEnd)
				break;

			// Split header. TODO: implement multiline headers (starts with SP character).
			const wchar_t* colonPos = wcschr(nextHeaderStart, L':');
			if(colonPos != NULL)
			{
				CString key(nextHeaderStart, int(colonPos - nextHeaderStart));
				CString value(colonPos + 1, int(nextHeaderEnd - colonPos - 1));
				value.Trim();
				int headerIndex = newHeaders.FindKey(key);
				if(headerIndex != -1)
				{
					newHeaders.GetValueAt(headerIndex).Add(value);
				}
				else
				{
					newHeaders.Add(key, CSimpleArray<CString>());
					newHeaders.GetValueAt(newHeaders.GetSize() - 1).Add(value);
				}
			}

			nextHeaderStart = nextHeaderEnd + 2;
		}
		while(nextHeaderStart < headers + headersLen);

		if(newHeaders.GetSize() > 0)
		{
			for(int i = 0; i < newHeaders.GetSize(); i++)
				Set(newHeaders.GetKeyAt(i), newHeaders.GetValueAt(i));
		}

		return S_OK;
	}

	bool GetMimeType(CString& mimeType)
	{
		int index = _headers.FindKey(HeaderContentType);
		if(index == -1)
			return false;

		CSimpleArray<CString> values = _headers.GetValueAt(index);
		if(values.GetSize() == 0)
			return false;

		const CString& contentType = values[0];
		int mimeTypeLen = contentType.Find(L';');
		if(mimeTypeLen == -1)
			mimeType = contentType;
		else
			mimeType.Append(contentType.GetString(), mimeTypeLen);
		return true;
	}

	CString ToString()
	{
		int numberOfHeaders = _headers.GetSize();

		CString headers;
		headers.Preallocate(100 + numberOfHeaders * 100);
		
		for(int i = 0; i < numberOfHeaders; i++)
		{
			const CString& key = _headers.GetKeyAt(i);
			const CSimpleArray<CString>& values = _headers.GetValueAt(i);
			for(int valueIndex = 0; valueIndex < values.GetSize(); valueIndex++)
			{
				headers.Append(key);
				headers.Append(L": ");
				headers.Append(values[valueIndex]);
				headers.Append(L"\r\n");
			}
		}
		return headers;
	}

};


